package com.源码分析.using;

import java.util.Arrays;
import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import reactor.core.publisher.Flux;

// using工厂方法能根据一个disposable资源创建流，它在响应式编程中实现了try-with-resources方法
public class UsingDemo {

	private static final Logger logger = LoggerFactory.getLogger(UsingDemo.class);

	public static void main(String[] args) {
		// 我们可以通过以下方法连接数据库
		Flux<String> ioRequestResults = Flux.using( // using方法可以将Connection实例的生命周期与其包装流的生命周期相关联，using方法需要知道如何创建disposable资源，在这种情况下，代码创建一个新连接
				Connection::newConnection,
				connection -> Flux.fromIterable(connection.getData()), // 然后，该方法必须知道如何将刚刚创建的资源转换为响应式流，在这种情况下，我们调用fromIterable方法
				Connection::close // 最后同样重要的是如何关闭资源
		);
		// 订阅开始，using操作符都会首先创建新连接，继而接着执行工作流(成功或失败)，然后关闭先前创建的连接。在这种情况下，连接的生命周期与流的生命周期绑定。操作符还可以在通知订阅者流终止之前或之后选择是否应该进行清除动作
		ioRequestResults.subscribe(
				data -> logger.info("received data: {}", data),
				e -> logger.info("error: {}", e.getMessage()),
				() -> logger.info("stream finished")
		);
	}

	private static class Connection implements AutoCloseable { // Connection管理一些内部资源，并通过实现AutoCloseable接口来通知它

		private final Random rnd = new Random();

		public Iterable<String> getData(){ // 模拟io操作，有时可能导致异常或返回带有有用数据的Iterable集合
			if(rnd.nextInt(10) < 3) {
				throw new RuntimeException("communication error!");
			}
			return Arrays.asList("some", "data");
		}

		@Override
		public void close() { // 释放内部资源，并且应该始终被调用，即使在getData执行期间发生错误也是如此
			logger.info("io connection closed!");
		}

		public static Connection newConnection() { // 静态工厂方法始终返回Connection类的新实例
			logger.info("io connection created");
			return new Connection();
		}

	}

}
